/*
 * @Author: yanjikun
 * @Date: 2022-04-21 15:12:57
 * @LastEditors: yanjikun
 * @LastEditTime: 2022-04-22 10:14:29
 * @Description: file content
 */

import {
  App,
  ComponentInternalInstance,
  createVNode,
  getCurrentInstance,
  nextTick,
  ref,
  render,
  SetupContext,
  unref
} from 'vue'
import { MyModal, MyModalInstance } from './modal'
import { HookModalProps } from './types'

let _app: App
export const useModal = () => {
  let _modalInstance: ComponentInternalInstance
  const modalRef = ref<MyModalInstance>()
  const appContext = _app?._context || getCurrentInstance()?.appContext
  /**当前模态框是否处于App.vue上下文中 */
  const isAppChild = ref(false)
  const getModalInstance = async () => {
    await nextTick()
    if (isAppChild.value && modalRef.value) {
      return modalRef.value
    }
    if (_modalInstance) {
      return _modalInstance
    }
    const container = document.createElement('div')
    const vnode = createVNode(MyModal)
    vnode.appContext = appContext
    render(vnode, container)
    _modalInstance = vnode.component!
    _modalInstance.props.closeModal = hide
    return _modalInstance
  }

  const setProps = async (props: HookModalProps) => {
    const instance = await getModalInstance()
    if (Object.is(instance, modalRef.value)) {
      ;(instance as MyModalInstance)?.setProps?.(props)
    } else {
      ;(instance as ComponentInternalInstance)?.exposed?.setProps?.(props)
    }
  }
  const hide = () => {
    setProps({ visible: false })
  }

  const show = async (props: HookModalProps) => {
    setProps({
      ...props,
      visible: true,
      closeModal: hide,
      isAppChild: unref(isAppChild)
    })
    await nextTick()
  }

  const ModalRender = (props: HookModalProps, { attrs, slots }: SetupContext) => {
    isAppChild.value = true
    return (
      <MyModal
        ref={modalRef}
        {...{ ...attrs, ...props, isAppChild: unref(isAppChild) }}
        v-slots={slots}
      />
    )
  }
  ModalRender.show = show
  ModalRender.hide = hide
  ModalRender.setProps = setProps
  return [ModalRender, modalRef] as const
}

export type ModalInstance = ReturnType<typeof useModal>

export const installUseModal = (app: App) => {
  _app = app
}
